<?php
	/**
	  * @name		Crypter
	  * @brief		Clase para cifrar cadenas, array, etc con una clave especifica
	  * @author		Hermann D. Schimpf <hschimpf@gschimpf.com>
	  * @license	http://www.gnu.org/licenses/gpl.html
	  *				Crypter - Clase para cifrar cadenas, array, etc con una clave especifica
	  *				Copyright © 2010 Hermann D. Schimpf
	  *				Este programa es software libre: usted puede redistribuirlo y/o modificarlo conforme a los términos de la Licencia Pública General de GNU publicada por la Fundación para el Software Libre, ya sea la versión 3 de esta Licencia o (a su elección) cualquier versión posterior.
	  *				Este programa se distribuye con el deseo de que le resulte útil, pero SIN GARANTÍAS DE NINGÚN TIPO; ni siquiera con las garantías implícitas de COMERCIABILIDAD o APTITUD PARA UN PROPÓSITO DETERMINADO. Para más información, consulte la Licencia Pública General de GNU.
	  *				Junto con este programa, se debería incluir una copia de la Licencia Pública General de GNU. De no ser así, ingrese a http://www.gnu.org/licenses
	  * @date		2009-12-30
	  * @version	0.1.2
  	**/

	final class Crypter extends MyDebuger implements MyVersions {
		/* version de la clase */
		private static $version			= 0;
		/* subversion de la clase */
		private static $subversion		= 1;
		/* numero de revision de la clase */
		private static $revision		= 2;

		/* resultado del cifrado / decifrado */
		private $result	= '';

		public function __construct($debug = False) {
			/* creamos el padre */
			parent::__construct($debug, __CLASS__);
		}

		public static final function getVersion() {
			/* retornamos la version actual de la clase */
			return 'v' . self::$version . '.' . self::$subversion . '.' . self::$revision;
		}

		public static function encrypt($value = Null, $key = Null, $debug = False) {
			try {
				try {
					/* creamos una instancia */
					$encrypt = new Crypter($debug);
					/* verificamos los valores recibidos */
					$encrypt->verificarValoresRecibidos($value, $key);
					/* ciframos el valor */
					$encrypt->cifrarDecifrarValor($value, $key);
					/* retornamos la cadena cifrada */
					return $encrypt->getResult();
				} catch (Exception $e) {
					/* capturamos todos los errores y los transformamos en mi excepcion */
					$encrypt->convertToMyException($e);
				}
			} catch (MyException $e) {
				/* si se produjo una excepcion la manejamos con el metodo 'show' */
				$encrypt->show($e->getMensaje());
			}
		}

		public static function decrypt($value = Null, $key = Null, $debug = False) {
			try {
				try {
					/* creamos una instancia */
					$encrypt = new Crypter($debug);
					/* verificamos los valores recibidos */
					$encrypt->verificarValoresRecibidos($value, $key, 'de');
					/* ciframos el valor */
					$encrypt->cifrarDecifrarValor($value, $key, False);
					/* retornamos la cadena cifrada */
					return $encrypt->getResult();
				} catch (Exception $e) {
					/* capturamos todos los errores y los transformamos en mi excepcion */
					$encrypt->convertToMyException($e);
				}
			} catch (MyException $e) {
				/* si se produjo una excepcion la manejamos con el metodo 'show' */
				$encrypt->show($e->getMensaje());
			}
		}

		private function verificarValoresRecibidos($value, $key, $type = False) {
			/* mostramos un mensaje */
			$this->show('Verificando valores recibidos..', False);
			/* verificamos si especifico una cadena a cifrar */
			if ($value === Null)
				/* salimos con una excepcion */
				$this->newException('No se especifico la cadena a ' . $type . 'cifrar');
			/* verificamos si especifico una clave para el cofrado */
			if ($key === Null)
				/* salimos con una excepcion */
				$this->newException('No se especifico la clave para realizar el ' . $type . 'cifrado');
			/* mostramos ok al mensaje */
			$this->showOK();
		}

		private function cifrarDecifrarValor($value, $key, $cifrar = True) {
			/* mostramos un mensaje */
			$this->show(($cifrar ? 'C' : 'Dec') . 'ifrando la cadena..', False);
			/* obtenemos la cadena */
			$value = (
				/* verificamos si vamos a cifrar o decifrar */
				$cifrar ?
				/* serializamos el valor */
				serialize($value) :
				/* decodificamos el valor y lo descomprimimos */
				gzuncompress(base64_decode($value))
			);
			/* ingresamos a un bucle */
			for ($i = 0; $i < strlen($value); $i++) {
				/* obtenemos el caracter actual */
				$char = substr($value, $i, 1);
				/* obtenemos el keycode del caracter */
				$keychar = substr($key, (($i % strlen($key)) -1), 1);
				/* armamos el nuevo caracter */
				$char = chr(
					/* verificamos si vamos a cifrar o decifrar */
					$cifrar ?
					/* sumamos las cadenas */
					ord($char) + ord($keychar) :
					/* restamos las cadenas */
					ord($char) - ord($keychar)
				);
				/* agregamos el caracter a la cadena final */
				$this->result .= $char;
			}
			/* almacenamos el resultado */
			$this->result = (
				/* verificamos si vamos a cifrar o decifrar */
				$cifrar ?
				/* comprimimos y codificamos el valor */
				base64_encode(gzcompress($this->result)) :
				/* deserializamos el valor */
				unserialize($this->result)
			);
			/* mostramos ok al mensaje */
			$this->showOK();
		}

		private function getResult() {
			/* retornamos el resultado */
			return $this->result;
		}
	}
?>